﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Script.Serialization;

namespace System
{
    public static class SystemWebExtensions
    {
        #region Object

        public static T GetValueOrDefault<TObj, T>(this TObj obj, Func<TObj, T> expectedValue,
                                                   T defaultValue = default(T)) where TObj : class
        {
            return obj == null ? defaultValue : expectedValue(obj);
        }

        #endregion

        #region String

        public static bool IsNullOrEmpty(this string value)
        {
            return String.IsNullOrEmpty(value);
        }

        public static string AdicionarMascaraCnpj(this string cnpj)
        {
            return cnpj.IsNullOrEmpty() ? null : String.Format(@"{0:00\.000\.000\/0000\-00}", Convert.ToInt64(cnpj));
        }

        public static string RemoverMascaraCnpj(this string cnpj)
        {
            return cnpj.IsNullOrEmpty()
                       ? null
                       : cnpj.Replace(".", String.Empty).Replace("/", String.Empty).Replace("-", String.Empty).Replace(
                           "_", String.Empty);
        }

        #endregion

        #region Boolean

        public static string GetString(this bool value)
        {
            return value ? "Sim" : "Não";
        }

        #endregion

        #region Enum

        /// <summary>
        /// Obtem a descricao do Enumerador
        /// </summary>
        /// <param name="enumerator"></param>
        /// <returns></returns>
        public static string GetDescription<TEnum>(TEnum enumerator)
        {
            //get the enumerator type
            Type type = enumerator.GetType();

            //get the member info
            MemberInfo[] memberInfo = type.GetMember(enumerator.ToString());

            //if there is member information
            if (memberInfo.Length > 0)
            {
                //we default to the first member info, as it's for the specific enum value
                object[] attributes = memberInfo[0].GetCustomAttributes(typeof (DescriptionAttribute), false);

                //return the description if it's found
                if (attributes.Length > 0)
                    return ((DescriptionAttribute) attributes[0]).Description;
            }

            //if there's no description, return the string value of the enum
            return enumerator.ToString();
        }

        public static string GetDescription(this Enum enumerator)
        {
            //get the enumerator type
            Type type = enumerator.GetType();

            //get the member info
            MemberInfo[] memberInfo = type.GetMember(enumerator.ToString());

            //if there is member information
            if (memberInfo.Length > 0)
            {
                //we default to the first member info, as it's for the specific enum value
                object[] attributes = memberInfo[0].GetCustomAttributes(typeof (DescriptionAttribute), false);

                //return the description if it's found
                if (attributes.Length > 0)
                    return ((DescriptionAttribute) attributes[0]).Description;
            }

            //if there's no description, return the string value of the enum
            return enumerator.ToString();
        }

        /// <summary>
        /// Obtem o Enumerador atraves de sua Descricao
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="descricao"></param>
        /// <returns></returns>
        public static T ToEnumFromDescription<T>(this string descricao)
        {
            //get the member info of the enum
            MemberInfo[] memberInfos = typeof (T).GetMembers();

            if (memberInfos.Length > 0)
            {
                //loop through the member info classes
                foreach (MemberInfo memberInfo in memberInfos)
                {
                    //get the custom attributes of the member info
                    object[] attributes = memberInfo.GetCustomAttributes(typeof (DescriptionAttribute), false);

                    //if there are attributes
                    if (attributes.Length > 0)
                        //if the description attribute is equal to the description, return the enum
                        if (((DescriptionAttribute) attributes[0]).Description == descricao)
                            return (T) Enum.Parse(typeof (T), memberInfo.Name);
                }
            }

            //this means the enum was not found from the description, so return the default
            return default(T);
        }

        public static IEnumerable<SelectListItem> ToSelectList<TEnum>(this TEnum enumObj,
                                                                      bool useIntValue,
                                                                      bool useDescriptionValue,
                                                                      string defaultOption = "Selecione")
            where TEnum : struct
        {
            Type type = typeof (TEnum);

            List<SelectListItem> values = (from object e in Enum.GetValues(type)
                                           select new SelectListItem
                                                      {
                                                          Value =
                                                              (useIntValue)
                                                                  ? Enum.Format(type, Enum.Parse(type, e.ToString()),
                                                                                "d")
                                                                  : e.ToString(),
                                                          Text =
                                                              (useDescriptionValue) ? GetDescription(e) : e.ToString()
                                                      }).ToList();

            if (!defaultOption.IsNullOrEmpty())
            {
                if (Enum.IsDefined(type, defaultOption))
                    values.Find(x => x.Text == defaultOption).Selected = true;
                else
                    values.Insert(0, new SelectListItem {Selected = true, Text = defaultOption});
            }

            return values;
        }

        public static IEnumerable<SelectListItem> ToSelectList<TEnum>(this TEnum enumObj,
                                                                      bool useIntValue,
                                                                      bool useDescriptionValue) where TEnum : struct
        {
            return ToSelectList(enumObj, useIntValue, useDescriptionValue, null);
        }

        #endregion

        #region Json

        public static string ToJson(this object obj)
        {
            var serializer = new JavaScriptSerializer();
            return serializer.Serialize(obj);
        }

        public static string ToJson(this object obj, int recursionDepth)
        {
            var serializer = new JavaScriptSerializer {RecursionLimit = recursionDepth};
            return serializer.Serialize(obj);
        }

        public static T FromJson<T>(this object obj)
        {
            if (obj == null)
                return default(T);
            var serializer = new JavaScriptSerializer();
            return serializer.Deserialize<T>(obj as string);
        }

        #endregion

        #region JqGridJson

        public static object ToJqGridJson<T>(this IEnumerable<T> lista,
                                             int paginaAtual,
                                             int registrosPorPagina,
                                             long totalRegistros)
        {
            var jsonData = new
                               {
                                   total = Math.Max(1, Math.Ceiling((double) totalRegistros/registrosPorPagina)),
                                   page = paginaAtual,
                                   rows = lista,
                                   records = totalRegistros
                               };

            return jsonData;
        }

        #endregion

        public static MvcHtmlString TextBoxForEx<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
                                                                    Expression<Func<TModel, TProperty>> expression,
                                                                    object htmlAttributes)
        {
            if (htmlHelper.ValidationMessageFor(expression) != null)
            {
                var attr = new RouteValueDictionary(htmlAttributes)
                               {{"title", htmlHelper.ValidationMessageFor(expression)}};
                return htmlHelper.TextBoxFor(expression, attr);
            }
            return htmlHelper.TextBoxFor(expression, htmlAttributes);
        }
    }
}

namespace System.Collections.Generic
{
    public static class ListExtensions
    {
        public static List<KeyValuePair<TKey, TValue>> ToKeyValuePairList<TKey, TValue>(
            this Dictionary<TKey, TValue> dictionary)
        {
            return dictionary == null
                       ? null
                       : dictionary.Select(item => new KeyValuePair<TKey, TValue>(item.Key, item.Value)).ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerable"></param>
        /// <param name="text"></param>
        /// <param name="value"></param>
        /// <param name="defaultOption"></param>
        /// <param name="selectedValue"></param>
        /// <returns></returns>
        public static SelectList ToSelectList<T>(this IEnumerable<T> enumerable,
                                                 Func<T, string> text,
                                                 Func<T, string> value,
                                                 string defaultOption,
                                                 string selectedValue = null)
        {
            List<SelectListItem> items = enumerable.Select(f => new SelectListItem
                                                                    {
                                                                        Text = text(f),
                                                                        Value = value(f),
                                                                    }).ToList();

            if (!defaultOption.IsNullOrEmpty())
                items.Insert(0, new SelectListItem
                                    {
                                        Text = defaultOption,
                                        Value = String.Empty
                                    });


            if (!selectedValue.IsNullOrEmpty())
                return new SelectList(items, "Value", "Text", selectedValue);

            return new SelectList(items, "Value", "Text");
        }

        public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> enumerable,
                                                                  Converter<T, TOutput> converter)
        {
            if (enumerable == null)
                throw new ArgumentNullException("enumerable");

            if (converter == null)
                throw new ArgumentNullException("converter");

            int size = enumerable.Count();

            var list = new List<TOutput>(size);

            for (int i = 0; i < size; i++)
                list.Add(converter(enumerable.ElementAt(i)));

            return list;
        }

        public static bool HasDuplicates<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector)
        {
            if (enumerable == null)
                throw new ArgumentNullException("enumerable");

            if (keySelector == null)
                throw new ArgumentNullException("keySelector");

            return enumerable.GroupBy(keySelector).Any(i => i.Count() > 1);
        }

        public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> selector)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            if (selector == null)
                throw new ArgumentNullException("selector");

            return source.Aggregate(TimeSpan.Zero, (current, item) => current + selector(item));
        }
    }
}